package com.lagou.rpc.server;

import com.lagou.rpc.common.ConfigKeeper;
import com.lagou.rpc.common.registry.RpcRegistryHandler;
import com.lagou.rpc.provider.RpcServerHandler;
import com.lagou.rpc.register.ProviderLoader;
import com.lagou.rpc.register.handler.RpcRegistryFactory;
import com.lagou.rpc.server.config.RpcServerConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import javafx.fxml.Initializable;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URL;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;

@Service
public class RpcServer implements InitializingBean, DisposableBean {

    @Autowired
    private RpcRegistryFactory registryFactory;
    private NioEventLoopGroup boosGroup;
    private NioEventLoopGroup workerGroup;
    private RpcServerConfig config;

    public void startServer() throws Exception{
        boosGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(boosGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        //心跳检测
                        pipeline.addLast(new IdleStateHandler(0,0, 9, TimeUnit.SECONDS));
                        //请求解码
                        pipeline.addLast(new StringDecoder());
                        //响应编码
                        pipeline.addLast(new StringEncoder());
                        //业务处理
                        pipeline.addLast(new RpcServerHandler());

                    }
                });
        String ip = "127.0.0.1";
        config.setIp(ip);
        int port = config.getPort();
        String applicationName = config.getApplicationName();
        //绑定端口
        ChannelFuture sync = serverBootstrap.bind(ip, port);

        //延迟注册
        if (config.getDelay() > 0) {
            Thread.sleep(config.getDelay());
        }
        System.out.println("==========开始注册==========");
        this.registry(ip, port, applicationName, config.getServices());
        System.out.println("==========启动成功==========");
        sync.channel().closeFuture().sync();

    }

    /**
     * 注册服务实例
     * @param ip
     * @param port
     * @param applicationName
     */
    public void registry(String ip, int port, String applicationName, Map<String, Object> instanceMap) {
        if (MapUtils.isEmpty(instanceMap)) {
            System.out.println("no service find");
            throw new RuntimeException("no service find");
        }
        try {
            RpcRegistryHandler registryHandler = registryFactory.getObject();
            if (null == registryHandler) {
                System.out.println("registryHandler is null");
                throw new RuntimeException("registryHandler is null");
            }
            instanceMap.entrySet().stream().forEach(objectEntry ->{
                registryHandler.registry(objectEntry.getKey(), ip, port);
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




    @Override
    public void destroy() throws Exception {
        if (null != boosGroup) {
            boosGroup.shutdownGracefully();
        }
        if (null != workerGroup) {
            workerGroup.shutdownGracefully();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, Object> instanceCacheMap = ProviderLoader.getInstanceCacheMap();

        config = RpcServerConfig.builder()
        .applicationName("rpc-provider")
        .port(ConfigKeeper.getInstance().getPort())
        .delay(3000)
        .services(instanceCacheMap)
        .provideSide(true)
        .build();

        //启动
        startServer();
    }
}
